#include "inc.h"
#include <string>

#define TAG_MAIN   "MAIN"
#define MY_BUFFER_SIZE 120

bool set_nonblock(SOCKET s) {
  u_long ul = 1;
  return ioctlsocket(s, FIONBIO, &ul) != SOCKET_ERROR;
}

struct my_buf {
  char *buf;
  int len;
  int alloced;
  my_buf(const char *_buf = 0, int _len = 0)
      : buf(0), len(0), alloced(0) {
    append(_buf, _len);
  }
  ~my_buf() { clear(); }
  bool append(const char *_buf, int _len) {
    if (!_buf || _len <= 0) return false;
    if (alloced < len + _len) {
      if (!this->realloc(len + _len))
        return false;
    }
    memcpy(buf + len, _buf, _len);
    len += _len;
    return true;
  }
  bool realloc(int size) {
    buf = (char*)::realloc(buf, size);
    return !!buf;
  }
  void clear() {
    if (buf) free(buf);
    buf = 0;
    len = 0;
    alloced = 0;
  }
  void empty() {
	  len = 0;
  }
};

int send_buf(SOCKET fd, const my_buf* buf) {
	if (!buf || buf->len <= 0) return -1;
	return send(fd, buf->buf, buf->len, 0);
}
int recv_buf(SOCKET fd, my_buf* buf) {
	char buf_[MY_BUFFER_SIZE];
	int len = recv(fd, buf_, MY_BUFFER_SIZE, 0);
	buf->append(buf_, len);
	show_hex(buf->buf, buf->len);
	return len;
}
bool dowork(SOCKET repeater, SOCKET winvnc) {
	my_buf buf1, buf2;
	int len;

	while (true) {
		do {
			buf1.empty();
			len = recv_buf(winvnc, &buf1);
			send_buf(repeater, &buf1);
		} while (len == MY_BUFFER_SIZE);
		if (len <= 0) return true;

		do {
			buf2.empty();
			len = recv_buf(repeater, &buf2);
			send_buf(winvnc, &buf2);
		} while (len == MY_BUFFER_SIZE);
		if (len <= 0) return true;
	}

	return true;
}

struct my_data {
  const char *repeater;
  std::string repeater_host;
  uint16_t repeater_port;
  uint16_t port;
};
bool on_accept(SOCKET fd_accept, void *udata) {
  my_data *md = (my_data*)udata;
  if (!md) return false;

  return client(md->repeater_host.c_str(), md->repeater_port, md
    , [&](SOCKET fd, void *udata) -> bool {

      //auto b1 = set_nonblock(fd_accept);
      //auto b2 = set_nonblock(fd);

		  return dowork(fd, fd_accept);

      my_buf buf1, buf2;
      char buf[MY_BUFFER_SIZE];
#if 0
	  while (true) {
		  fd_set read_set;
		  FD_ZERO(&read_set);
		  FD_SET(fd_accept, &read_set);
		  FD_SET(fd, &read_set);

		  int maxfd = MAX(fd_accept, fd);
		  int active_cnt = select(maxfd + 1, &read_set, NULL, NULL, NULL);
		  if (active_cnt < 0) {
			  MY_LOG(TAG_MAIN, "select < 0.");
		  }

		  if (FD_ISSET(fd_accept, &read_set)) {
			  int ret = 1;
			  while (ret > 0) {
				  ret = recv(fd_accept, buf, MY_BUFFER_SIZE, 0);
				  if (ret > 0) buf1.append(buf, ret);
			  }
			  if (buf2.len > 0) {
				  int r = send(fd_accept, buf2.buf, buf2.len, 0);
			  }
		  }
		  if (FD_ISSET(fd, &read_set)) {
			  int ret = 1;
			  while (ret > 0) {
				  ret = recv(fd, buf, MY_BUFFER_SIZE, 0);
				  if (ret > 0) buf2.append(buf, ret);
			  }
			  if (buf1.len > 0) {
				  int r = send(fd, buf1.buf, buf1.len, 0);
			  }
		  }
	  }
	  return true;
#else
	  do {
		  int len = recv(fd_accept, buf, 100, 0);
		  show_hex(buf, len);
		  len = send(fd, buf, len, 0);

		  len = recv(fd_accept, buf, MY_BUFFER_SIZE, 0);
		  show_hex(buf, len);
		  len = send(fd, buf, len, 0);

		  len = recv(fd, buf, 20, 0);
		  show_hex(buf, len);
		  len = send(fd_accept, buf, len, 0);

		  len = recv(fd_accept, buf, MY_BUFFER_SIZE, 0);
		  show_hex(buf, len);
		  len = send(fd, buf, len, 0);

		  len = recv(fd, buf, MY_BUFFER_SIZE, 0);
		  show_hex(buf, len);
		  len = send(fd_accept, buf, len, 0);

		  /*
		  if (len > 0) buf1.append(buf, len);
		  len = recv(fd, buf, MY_BUFFER_SIZE, 0);
		  if (len > 0) buf2.append(buf, len);

		  if (buf1.len > 0) {
			  MY_LOG(TAG_MAIN, "----- winvnc -----\n");
			  show_hex(buf1.buf, buf1.len);
			  len = send(fd, buf1.buf, buf1.len, 0);
			  buf1.clear();
		  }

		  if (buf2.len > 0) {
			  MY_LOG(TAG_MAIN, "----- viewver -----\n");
			  show_hex(buf2.buf, buf2.len);
			  len = send(fd_accept, buf2.buf, buf2.len, 0);
			  buf2.clear();
		  }*/
	  } while (buf1.len || buf2.len);
	  return true;
#endif
     
    });
}

int user_main(int argc, char *argv[]) {
  if (argc != 3) {
    MY_LOG(TAG_MAIN, "#> winvnc_proxy <port> <repeater host:port>");
    MY_LOG(TAG_MAIN, "such as:  winvnc_proxy 5902 192.168.5.7:5901");
    return 0;
  }

  my_data udata;
  {
    udata.port = atoi(argv[1]);
    udata.repeater = argv[2];
    const char *spe = strstr(udata.repeater, ":");
    udata.repeater_port = atoi(spe + 1);
    udata.repeater_host.assign(udata.repeater, spe - udata.repeater);
  }
  
  if (!server(udata.port, &udata, on_accept)) {
    MY_LOG(TAG_MAIN, "create server error.");
    return 0;
  }

  return 0;
}